package org.gpp.proj1.robot;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.gpp.proj1.bone.Bone;
import org.gpp.proj1.bone.BoneStructure;
import org.gpp.proj1.robot.action.executor.ActionExecutor;
import org.gpp.proj1.robot.part.EquippedPart;
import org.gpp.proj1.robot.part.SparePart;
import org.gpp.proj1.robot.part.emissor.Emissor;

import com.jme.scene.Node;
import com.jme.scene.Spatial;

/**
 * Class that implements a robot, with skeletal animation
 *  
 * @author Paolo Victor, paolovictor@gmail.com
 */
public class RobotImpl implements Robot {

	protected Map<String, EquippedPart> equippedParts;
	
	protected BoneStructure boneStructure;
	
	protected Node robotNode;
	
	public RobotImpl( BoneStructure boneStructure ) {
		this.robotNode = new Node( "Robot" );
		this.robotNode.attachChild( boneStructure.getRoot() );
		this.boneStructure = boneStructure;
		this.equippedParts = new HashMap<String, EquippedPart>();
	}

	public void setPart( String boneGroup, SparePart part ) {

		// Sets the bone's models
		Set<String> models = part.getModelNames();
		Map<String, Bone> group = this.boneStructure.getBoneGroup( boneGroup );
		
		if( group != null ) {
			for( String modelName : models ) {
				Bone bone = group.get( modelName );				
				Spatial modelNode = part.getModel( modelName );
				
				if( bone != null && modelNode != null ) {
					modelNode.setName( modelName );					
	
					bone.detachChildNamed( modelName );
					bone.attachChild( part.getModel( modelName ) );
					
					modelNode.updateRenderState();
				}
			}
			
			this.equippedParts.put( boneGroup, new EquippedPart( part, this, group ) );
		}
	}

	public void setAnimation( String animation ) {
		this.boneStructure.getRoot().setAnimation( animation );
	}

	public void attachEmissor(String boneName, Emissor emissor) {

		boneStructure.getBone( boneName ).attachChild( emissor.getEmissorNode( boneName ) );
	}

	public void removeEmissor(String boneName, Emissor emissor) {
		
		boneStructure.getBone( boneName ).detachChildNamed( emissor.getEmissorNode( boneName ).getName() );
	}

	public Node getNode() {

		return robotNode;
	}

	public void updateAnimation(float tpf) {
		
		boneStructure.getRoot().updateAnimation( tpf );
	}

	public List<String> getExecutableActions() {
		List<String> results = new LinkedList<String>();
		Set<String> groups = equippedParts.keySet();
		
		for( String group : groups ) {
			EquippedPart part = equippedParts.get( group );
			List<String> actions =  part.getActions();
			for( String action : actions ) {
				results.add( action );
			}
		}
		
		return results;
	}

	public void executeAction(String partGroup, String action) {
		executeAction( partGroup, action, null );
	}

	public void executeAction(String partGroup, String action, List<Robot> targets) {
		EquippedPart part = equippedParts.get( partGroup );
		part.assignGroup( partGroup );
		
		System.out.println( action );
		ActionExecutor executor = part.getActionExecutor( action );
		executor.setTargets( targets );
		
		if( executor != null ) {
			new Thread( executor ).start();
		}
	}
}